#include "transContentFuncCallQueryTarget.hpp"

////////////////////////////////////////////////////////////////////////////////
/// query target devices for target devices
/// send packet to stack use data fifo
///
/// return:
///		E_TRANC_TIMEOUT: query info timeout
///		E_TRANC_ParamError: parameter error, or forget call some setters
///		E_TRANC_NONBLOCK: call method use sync style
///		E_TRANC_BUFFER_FULL: the client buffer count reached the max limits
///		result: query Result;
////////////////////////////////////////////////////////////////////////////////
int TransContentFuncCallQueryTarget::query(deviceInfo* dInfo){
	int length = 0, bufferIndex;
	char* buffer = NULL;
	char logPath[FILE_NAME_LEN]={0};

	//check fileds
	if(localPort <= 0 || (queryCondType < QUERY_DEVICE_COND_USERNICK || queryCondType > QUERY_DEVICE_COND_TTL) || queryValueLen <= 0){
		log_error("query method check need fileds value failed!");
		return E_TRANC_ParamError;
	}

	//use block or sync method
	if(qtcb == NULL && dInfo == NULL){
		log_error("callback is NULL, means use block style, but the parameter deviceInfo for method is NULL");
		return E_TRANC_ParamError;
	}

	if(target.serial_id <= 0){
		log_error("target serial id error <= 0");
		return E_TRANC_ParamError;
	}

	//construct packet
	bufferIndex = TransContentMemory::getInstance()->getBuffer(&buffer);
	if(bufferIndex == E_TRANC_BUFFER_FULL){
		log_error("construct ");
		return bufferIndex;
	}

	log_info(" TransContentFuncCallQueryTarget::query==> begin to construct the packet: ");
	setPacketMainMessage(buffer, message_type_inner_functionCall_queryTarget_request);
	setPacketSubMessageCode(buffer, 0);
	setPacketLocalPort(buffer, localPort);
	setPacketTarget(buffer, target);
	setPacketQueryValueType(buffer, queryCondType);
	setPacketQueryValueLen(buffer, queryValueLen);
	setPacketQueryValue(buffer, queryCondValue, queryValueLen);
	setPacketLength(buffer, 18+queryValueLen);
	*(short*(buffer)) = (short)(16 + queryValueLen);
	log_info("construct packet sucessfully, begin to dump packet");
	TransContentSetting::getDumpPacketFileName(logPath, FILE_NAME_LEN);
	dumpPacket(buffer, DUMP_PROTOCOL_PACKET_OUT, logPath);

	/// send packet to data, use data fifo
	if(TransContentDispatcher::getInstance()->sendDataDataToStack(buffer, 18+queryValueLen) != E_TRANC_SUCESS){
		log_error("send data to stack failed!!");
		return E_TRANC_InnerLogicError;
	}

	/// wait or return
	if(qtcb != NULL){
		log_info("TransContentFuncCallQueryTarget::query callback Not NULL, use snyc style");
		return E_TRANC_NONBLOCK; 
	}

	///wait
	pthread_mutex_lock(&waitMutex);
	if(pthread_cond_timedwait(&waitCond, &waitMutex, &ts) == ETIMEDOUT){
		pthread_mutex_unlock(&waitMutex);
		canBeRemoved = 1;
		return E_TRANC_TIMEOUT;
	}
	pthread_mutex_unlock(&waitMutex);
	if(operationResult == 1)
		*dInfo = resultInfo;
	log_info("nsContentFuncCallQueryTarget::query==> query finished! sucessfully");
	canBeRemoved = 1;
	return operationResult;
}

//////////////////////////////////////////////////////////////////////////////////
/// wait 10s for the sync mehtod finished, or kill the thread
//////////////////////////////////////////////////////////////////////////////////
int TransContentFuncCallQueryTarget::response(char* content, int index){
	int mainCode = 0;
	char pathName[FILE_NAME_LEN] = {0};
	debug_enter();
	memset(&resultInfo, 0x00, sizeof(resultInfo));
	mainCode = getPacketMainMessage(content, DUMP_PROTOCOL_PACKET_IN);
	if(mainCode != message_type_inner_functionCall_queryTarget_response){
		logd_error("function query, the protocol not querytarget response, continue to post");
		return RESPONSE_RESULT_POST_CONITNUE;
	}
	operationResult = getPacketQueryResult(content);

	if(operationResult == 1){
		/// get info
		resultInfo.showMe = getPacketDeviceInfoShowMe(content);
		resultInfo.nickLen = getPacketDeviceInfoNickLen(content);
		getPacketDeviceInfoNick(content, &(resultInfo.userNick), MAX_DEVICENICK_LEN);
		resultInfo.deviceIdLen = getPacketDeviceInfoDeviceIdLen(content);
		getPacketDeviceInfoDeviceId(content, &(resultInfo.deviceId), MAX_DEVICEID_LEN);
		getPacketDeviceInfoDeviceIMEI(content, &(resultInfo.deviceIMEI), MAX_DEVICE_IMEI);
		resultInfo.ttl = getPacketDeviceInfoTTL(content);

		logd_info("beign to dump response packet: ");
		TransContentSetting::getDumpPacketFileName(pathName, FILE_NAME_LEN);
		dumpPacket(content, DUMP_PROTOCOL_PACKET_IN, pathName);
	}
	logd_info("release the response packet: ");
	TransContentMemory::getInstance()->releaseBuffer(index);

	queryFinish();
	return RESPONSE_RESULT_NOACTION;
}

void TransContentFuncCallQueryTarget::queryFinish(){
	debug_enter();
	if(qtcb != NULL){
		logd_info("TransContentFuncCallQueryTarget::response==> callback not null, start a new thread to call the callBack");
		TransContentThreadPool::getInstance()->addTask(finshCallbackRoutem, this);
		return;
	}
	log_info("TransContentFuncCallQueryTarget::response==> callback null, will use block style");
	pthread_mutex_lock(&waitMutex);
	pthread_cond_signal(&waitCond);
	pthread_mutex_unlock(&waitMutex);
	debug_leave();
	return;
}

void* TransContentFuncCallQueryTarget::finshCallbackRoutem(void* p){
	(TransContentFuncCallQueryTarge*(p))->finshCallbackIns();
	return NULL;
}

void TransContentFuncCallQueryTarget::finshCallbackIns(){
	qtcb(&resultInfo);
	canBeRemoved = 1;
}
